package com.todo.strategy.online.application.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.api.client.util.Lists;
import com.todo.common.common.entity.response.page.PageResult;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.exception.BizException;
import com.todo.component.redis.RedisService;
import com.todo.strategy.common.constant.StrategyOnlineKeyBuild;
import com.todo.strategy.common.enums.PlanRelationSceneEnum;
import com.todo.strategy.common.enums.StrategyStatusEnum;
import com.todo.strategy.online.application.convert.StrategyConvert;
import com.todo.strategy.online.application.entity.bo.*;
import com.todo.strategy.online.application.entity.condition.StrategyInfoConditionBO;
import com.todo.strategy.online.application.service.StrategyInfoService;
import com.todo.strategy.online.application.mq.entity.UStrategyStatusChangeEntity;
import com.todo.strategy.online.application.mq.sender.UStrategyMqSender;
import com.todo.strategy.online.application.service.PlanRelationService;
import com.todo.strategy.online.application.service.PlanSetService;
import com.todo.strategy.online.infrastructure.entity.condition.StrategyInfoCondition;
import com.todo.strategy.online.infrastructure.entity.po.StrategyInfoPO;
import com.todo.strategy.online.infrastructure.helper.es.entity.BasicStrategyEntity;
import com.todo.strategy.online.infrastructure.helper.es.mapper.BasicStrategyEntityMapper;
import com.todo.strategy.online.infrastructure.repository.StrategyInfoRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (StrategyInfo)表服务实现类
 *
 * @author zhangwenxiang
 * @since 2024-03-04 00:19:49
 */
@Slf4j
@Service("strategyInfoService")
public class StrategyInfoServiceImpl implements StrategyInfoService {

    @Value("${strategy.default.examine:false}")
    private Boolean defaultExamine;

    @Resource
    private StrategyInfoRepository strategyInfoRepository;
    @Resource
    private PlanSetService planSetService;
    @Resource
    private PlanRelationService planRelationService;
    @Resource
    private RedisService redisService;
    @Resource
    private BasicStrategyEntityMapper basicStrategyEntityMapper;
    @Resource
    private UStrategyMqSender uStrategyMqSender;

    @Override
    public Boolean insertStrategyInfo(StrategyInfoBO strategyInfoBO) {
        if (strategyInfoBO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        StrategyInfoBO alreadyData = queryStrategyInfoPOByPlanId(strategyInfoBO.getUserId(), strategyInfoBO.getPlanId());
        if (alreadyData != null) {
            log.error("StrategyInfoService#insertStrategyInfo 新增攻略信息失败 存在用户和清单记录查询数据，默认不操作 strategyInfoBO：【{}】", JSONObject.toJSONString(strategyInfoBO));
            throw new BizException(BizErrorCodeEnum.SUCCESS_EXIST, "当前计划清单对应攻略已经存在");
        }
        //默认草稿模式
        strategyInfoBO.setStatus(StrategyStatusEnum.DRAFT);
        StrategyInfoPO strategyInfoPO = StrategyConvert.convertToStrategyInfoPO(strategyInfoBO);
        Boolean insertResult = strategyInfoRepository.insertStrategyInfoPO(strategyInfoPO);
        if (insertResult) {
            if (!defaultExamine) {
                //默认不执行情况下直接交由人工审核处理
                updateStrategyStatus(strategyInfoPO.getId(), StrategyStatusEnum.POSTED, StrategyStatusEnum.AUTO_EXAMINE_FAILED);
            } else {
                doStrategyStatusChangeMQ(strategyInfoPO.getId(), StrategyStatusEnum.POSTED);
            }
        }
        return insertResult;
    }

    @Override
    public Boolean updateStrategyInfo(StrategyInfoBO strategyInfoBO) {
        if (strategyInfoBO == null || strategyInfoBO.getId() == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        StrategyInfoBO alreadyData = queryStrategyInfoById(strategyInfoBO.getId());
        if (alreadyData == null) {
            log.error("StrategyInfoService#updateStrategyInfo 更新攻略信息失败 不存在用户和清单记录查询数据，默认不操作 strategyInfoBO：【{}】", JSONObject.toJSONString(strategyInfoBO));
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST, "当前数据不存在");
        }
        if (!alreadyData.getPlanId().equals(strategyInfoBO.getPlanId())) {
            log.error("StrategyInfoService#updateStrategyInfo 更新攻略信息失败 清单记录Id不匹配，默认不操作 strategyInfoBO：【{}】", JSONObject.toJSONString(strategyInfoBO));
            throw new BizException(BizErrorCodeEnum.ILLEGAL_OPERATION, "当前数据与计划清单不匹配");
        }
        //默认更新情况下状态为提交待验证
        strategyInfoBO.setStatus(StrategyStatusEnum.POSTED);
        StrategyInfoPO strategyInfoPO = StrategyConvert.convertToStrategyInfoPO(strategyInfoBO);
        Boolean updateResult = strategyInfoRepository.updateStrategyInfoPOById(strategyInfoPO);
        if (updateResult) {
            if (!defaultExamine) {
                //默认不执行情况下直接交由人工审核处理
                updateStrategyStatus(strategyInfoPO.getId(), StrategyStatusEnum.POSTED, StrategyStatusEnum.AUTO_EXAMINE_FAILED);
            } else {
                doStrategyStatusChangeMQ(strategyInfoPO.getId(), StrategyStatusEnum.POSTED);
            }
        }
        return updateResult;
    }

    @Override
    public StrategyInfoBO queryStrategyInfoById(Long id) {
        if (id == null || id < 0) {
            return null;
        }
        String detailKey = StrategyOnlineKeyBuild.strategyUserInfoKey(id);
        String cacheData = redisService.get(detailKey);
        if (StringUtils.isNotBlank(cacheData)) {
            return JSONObject.parseObject(cacheData, StrategyInfoBO.class);
        }
        StrategyInfoPO strategyInfoPO = strategyInfoRepository.queryStrategyInfoPOById(id);
        StrategyInfoBO strategyInfoBO = StrategyConvert.convertToStrategyInfoBO(strategyInfoPO);
        redisService.set8H(detailKey, JSONObject.toJSONString(strategyInfoBO));
        return strategyInfoBO;
    }

    @Override
    public StrategyInfoBO queryStrategyInfoPOByPlanId(Long userId, Long planId) {
        if (userId == null || planId == null || planId < 0 || userId < 0) {
            return null;
        }
        String relationKey = StrategyOnlineKeyBuild.strategyUserPlanRelation(userId, planId);
        if (redisService.hasKey(relationKey)) {
            Long strategyId = Long.valueOf(redisService.get(relationKey));
            return queryStrategyInfoById(strategyId);
        }
        StrategyInfoPO strategyInfoPO = strategyInfoRepository.queryStrategyInfoPOByPlanId(userId, planId);
        StrategyInfoBO strategyInfoBO = StrategyConvert.convertToStrategyInfoBO(strategyInfoPO);
        redisService.set8H(relationKey, String.valueOf(strategyInfoBO.getId()));
        return strategyInfoBO;
    }

    @Override
    public Boolean removeStrategyInfoById(Long id) {
        if (id == null || id < 0) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        StrategyInfoBO strategyInfoBO = queryStrategyInfoById(id);
        if (strategyInfoBO == null) {
            log.info("StrategyInfoService#removeStrategyInfoById 根据主键删除攻略信息完成，查询数据为空，默认删除成功 id：【{}】", id);
            return true;
        }
        Boolean updated = strategyInfoRepository.removeStrategyInfoPOById(id);
        if (updated) {
            String detailKey = StrategyOnlineKeyBuild.strategyUserInfoKey(id);
            redisService.del(detailKey);
            String relationKey = StrategyOnlineKeyBuild.strategyUserPlanRelation(strategyInfoBO.getUserId(), strategyInfoBO.getPlanId());
            redisService.del(relationKey);

            LambdaEsQueryWrapper<BasicStrategyEntity> wrapper = new LambdaEsQueryWrapper<>();
            wrapper.eq(BasicStrategyEntity::getMysqlId, id);
            basicStrategyEntityMapper.delete(wrapper);
        }
        return updated;
    }

    @Override
    public Boolean updateStrategyStatus(Long id, StrategyStatusEnum oldStatus, StrategyStatusEnum newStatus) {
        if (id == null || id < 0 || oldStatus == null || newStatus == null) {
            return false;
        }
        if (oldStatus == newStatus) {
            return true;
        }
        if (oldStatus.equals(StrategyStatusEnum.DISABLE)) {
            log.error("StrategyInfoService#updateStrategyStatus 更新攻略状态失败 已废弃的状态无法操作 strategyId:{}", id);
            throw new BizException(BizErrorCodeEnum.STRATEGY_STATUS_OPERATE_PROHIBITED);
        }
        StrategyInfoBO strategyInfoBO = queryStrategyInfoById(id);
        if (strategyInfoBO == null) {
            return false;
        }
        if (strategyInfoBO.getStatus().equals(newStatus)) {
            return true;
        }
        Boolean updated = strategyInfoRepository.updateStrategyStatus(id, oldStatus, newStatus);
        if (updated) {
            redisService.del(StrategyOnlineKeyBuild.strategyUserInfoKey(id));
            doStrategyStatusChangeMQ(id, newStatus);
        }
        return updated;
    }

    @Override
    public PageResult<StrategyInfoBO> queryStrategyInfoByCondition(StrategyInfoConditionBO strategyInfoCondition) {
        if (strategyInfoCondition == null) {
            return new PageResult<>();
        }
        StrategyInfoCondition condition = StrategyConvert.convertToStrategyInfoCondition(strategyInfoCondition);
        PageResult<StrategyInfoPO> pageResult = strategyInfoRepository.queryStrategyInfoPOByCondition(condition);
        if (pageResult == null) {
            return new PageResult<>();
        }
        PageResult<StrategyInfoBO> result = new PageResult<>();
        result.setPageNum(pageResult.getPageNum());
        result.setPageSize(pageResult.getPageSize());
        result.setResults(pageResult.getResults() == null ? null : pageResult.getResults().stream().map(StrategyConvert::convertToStrategyInfoBO).collect(Collectors.toList()));
        result.setTotal(pageResult.getTotal());
        result.setPageCount(pageResult.getPageCount());
        result.setCurrentIndex(pageResult.getCurrentIndex());
        result.setHasNext(pageResult.isHasNext());
        return result;
    }

    @Override
    public StrategyDetailBO queryStrategyDetailById(Long strategyId) {
        if (strategyId == null || strategyId < 0) {
            return null;
        }
        StrategyInfoBO strategyInfoBO = queryStrategyInfoById(strategyId);
        if (strategyInfoBO == null) {
            log.warn("StrategyInfoService#queryStrategyDetailById 根据攻略id查询攻略详情完成，攻略信息为空，默认返回空 strategyId：【{}】", strategyId);
            return null;
        }
        PlanSetBO planSetBO = planSetService.queryPlanSetById(strategyInfoBO.getPlanId());
        if (planSetBO == null) {
            log.warn("StrategyInfoService#queryStrategyDetailById 根据攻略id查询攻略详情完成，清单信息为空，默认返回空 strategyId：【{}】", strategyId);
            return null;
        }
        List<PlanRelationBO> planRelationBOList = planRelationService.queryPlanRelationByBizId(planSetBO.getPlanId(), PlanRelationSceneEnum.USER_STRATEGY);
        StrategyDetailBO strategyDetailBO = new StrategyDetailBO();
        strategyDetailBO.setStrategyInfoBO(strategyInfoBO);
        strategyDetailBO.setPlanSetBO(planSetBO);
        strategyDetailBO.setPlanRelationBOList(planRelationBOList);
        return strategyDetailBO;
    }

    @Override
    public List<StrategyInfoBO> queryStrategyInfoByIdList(List<Long> strategyIdList) {
        if (CollectionUtils.isEmpty(strategyIdList)) {
            return Lists.newArrayList();
        }
        List<StrategyInfoPO> strategyInfoPOList = strategyInfoRepository.queryStrategyInfoByIdList(strategyIdList);
        if (CollectionUtils.isEmpty(strategyInfoPOList)) {
            return Lists.newArrayList();
        }
        return StrategyConvert.convertToStrategyInfoBOList(strategyInfoPOList);
    }

    @Override
    public Boolean updateUserStrategyCount(UserStrategyCountBO countBO) {
        if (countBO == null) {
            return false;
        }
        StrategyInfoBO strategyInfoBO = queryStrategyInfoById(countBO.getStrategyId());
        if (strategyInfoBO == null) {
            return false;
        }
        StrategyInfoPO strategyInfoPO = new StrategyInfoPO();
        strategyInfoPO.setId(countBO.getStrategyId());
        strategyInfoPO.setViewCount(countBO.getSeeCount());
        strategyInfoPO.setLikeCount(countBO.getLikeCount());
        strategyInfoPO.setCollectCount(countBO.getCollectCount());
        strategyInfoPO.setCommentCount(countBO.getCommentCount());
        Boolean updated = strategyInfoRepository.updateStrategyInfoPOById(strategyInfoPO);
        if (updated) {
            redisService.del(StrategyOnlineKeyBuild.strategyUserInfoKey(countBO.getStrategyId()));
            BasicStrategyEntity strategyEntity = new BasicStrategyEntity();
            LambdaEsQueryWrapper<BasicStrategyEntity> wrapper = new LambdaEsQueryWrapper<>();
            wrapper.eq(BasicStrategyEntity::getMysqlId, countBO.getStrategyId());
            wrapper.set(BasicStrategyEntity::getLikeCount, countBO.getLikeCount());
            wrapper.set(BasicStrategyEntity::getViewCount, countBO.getSeeCount());
            wrapper.set(BasicStrategyEntity::getCommentCount, countBO.getCommentCount());
            wrapper.set(BasicStrategyEntity::getCollectCount, countBO.getCollectCount());
            basicStrategyEntityMapper.update(strategyEntity, wrapper);
        }
        return true;
    }

    private void doStrategyStatusChangeMQ(Long id, StrategyStatusEnum currentStatus) {
        UStrategyStatusChangeEntity entity = new UStrategyStatusChangeEntity();
        entity.setStrategyId(id);
        entity.setCurrentStatus(currentStatus);
        uStrategyMqSender.sendUStrategyStatusChange(entity, 0);
        log.info("StrategyInfoService#doStrategyStatusChangeMQ 发送攻略状态变更消息，id：【{}】，currentStatus：【{}】", id, currentStatus);
    }
}
